package club.kynb.mall.application.listener;

import club.kynb.mall.application.model.model.event.OrderCanceledEvent;
import club.kynb.mall.application.model.model.event.OrderConfirmEvent;
import club.kynb.mall.application.model.model.event.OrderPayNotifyEvent;
import club.kynb.mall.application.model.model.event.OrderSubmitSuccessEvent;
import club.kynb.mall.application.repository.OrderRepository;
import club.kynb.mall.order.api.IOrderService;
import club.kynb.mall.order.api.IShoppingCartService;
import club.kynb.mall.order.constant.OrderConstant;
import club.kynb.mall.order.constant.OrderPayStatusEnum;
import club.kynb.mall.order.constant.OrderStatusEnum;
import club.kynb.mall.order.model.dto.OrderAndDetailsDTO;
import club.kynb.mall.order.model.dto.OrderDTO;
import club.kynb.mall.payment.constant.PayOrderTypeEnum;
import club.kynb.mall.product.api.ICouponService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.pizza.common.web.exception.Errors;
import org.pizza.event.annotation.AsyncEventListener;
import org.pizza.util.Checker;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Component;
import org.springframework.transaction.support.TransactionTemplate;

import java.util.Date;
import java.util.Optional;

/**
 * @author kynb_club@163.com
 * @since 2020/12/25 2:01 下午
 */
@Slf4j
@Component
@AllArgsConstructor
public class OrderEventListener {
    private final IOrderService iOrderService;
    private final ICouponService iCouponService;
    private final RedissonClient redissonClient;
    private final TransactionTemplate transactionTemplate;
    private final IShoppingCartService iShoppingCartService;
    private final OrderRepository orderRepository;

    @AsyncEventListener
    public void onOrderPayNotifyEvent(OrderPayNotifyEvent event){
        log.info("订单：{} 通知状态：{}  支付通知事件开始  >>>", event.getInnerOrderNo(),event.getStatusEnum());

        PayOrderTypeEnum orderTypeEnum = event.getOrderTypeEnum();
        RLock lock = redissonClient.getLock(String.format(OrderConstant.NOTIFY_ORDER_LOCK,orderTypeEnum.getCode(), event.getInnerOrderNo()));
        boolean isLocked = false;
        try {
            Checker.ifNotThrow(isLocked = lock.tryLock(), () -> Errors.BIZ.exception(String.format(" %S订单:[%s] 支付回调并发异常",orderTypeEnum.getDesc(), event.getInnerOrderNo())));
            switch (orderTypeEnum){
                case NORMAL:
                    notifyOrder(event);
                    break;
                default: break;
            }
            log.info("订单：{} 通知状态：{}  支付通知处理完成  >>>", event.getInnerOrderNo(),event.getStatusEnum());
        } catch (Exception e) {
            log.error("订单：{} 支付成功通知处理失败",event.getInnerOrderNo(),e);
        }finally {
            if (isLocked) {
                lock.unlock();
            }
        }

    }

    @AsyncEventListener
    public void onSubmitOrderSuccessEvent(OrderSubmitSuccessEvent event) {
        //TODO 支付成功后清空？
        log.info("订单：{} ,用户ID：{} 提交成功清空购物车选中商品 >>>", event.getInnerOrderNo(), event.getUserId());
        iShoppingCartService.clearShoppingCart(event.getUserId());
        //清空缓存的预订单
        log.info("订单：{} ,用户ID：{} 提交成功清空缓存的预订单 >>>", event.getInnerOrderNo(), event.getUserId());
        orderRepository.clearPreOrderCache(event.getInnerOrderNo());
    }

    @AsyncEventListener
    public void onOrderCanceledEvent(OrderCanceledEvent event) {
        log.info("订单：{} 取消事件  >>>", event.getInnerOrderNo());
        final Optional<OrderAndDetailsDTO> optional = iOrderService.getByOrderAndDetails(event.getInnerOrderNo());
        if (optional.isPresent()) {
            //回退优惠券
            final OrderAndDetailsDTO orderAndDetailsDTO = optional.get();
            transactionTemplate.executeWithoutResult(transactionStatus -> {
                iCouponService.backCoupon(orderAndDetailsDTO.getUserId(),orderAndDetailsDTO.getUserCouponId());
                //回退库存
                //TODO 库存回退
            });
        } else {
            log.error("订单取消事件，订单编号：{} 没有找到对应的订单，需要排查处理", event.getInnerOrderNo());
        }
    }

    @AsyncEventListener
    public void onConfirmOrderSuccessEvent(OrderConfirmEvent event) {
        log.info("订单：{} 确认收货事件  >>>", event.getInnerOrderNo());
        final Optional<OrderDTO> optional = iOrderService.getOrderBy(event.getInnerOrderNo());
        if (optional.isPresent()) {
            log.info("订单：{} 确认收货事件  >>>", event.getInnerOrderNo());
        }else {
            log.error("订单取消事件，订单编号：{} 没有找到对应的订单，需要排查处理", event.getInnerOrderNo());
        }
    }




    private void notifyOrder(OrderPayNotifyEvent event){
        OrderDTO dto = new OrderDTO();
        dto.setInnerOrderNo(event.getInnerOrderNo());
        dto.setOrderStatus(OrderPayStatusEnum.PAID.equals(event.getStatusEnum()) ? OrderStatusEnum.UN_DELIVERY.code() : null);
        dto.setPayStatus(OrderPayStatusEnum.PAID.equals(event.getStatusEnum()) ? event.getStatusEnum().getStatus() : null);
        dto.setPayFinishTime(event.getPayTime());
        dto.setUpdateTime(new Date());
        iOrderService.updateByOrderNo(dto);
    }

}
